/* eslint-disable no-unused-vars */
import ArrayList from "../../util/ArrayList";
import namespace from "../../namespace";

const RECT_POINT_WIDTH = 6;
const RECT_POINT_HEIGHT = 6;
const RECT_POINT_BG_COLOR = "#0087ff";
const RECT_POINT_HIGHLIGHT_BG_COLOR = "red";

/**
 * 多边形绘制策略
 * 退出绘制情况:
 * 1. 键盘监听事件 ESC
 * 2. 非画布区域点击
 * 3. 其他
 */
export class PolygonPolicy extends namespace.policy.canvas.UniquePolicy {
  NAME = "namespace.policy.canvas.PolygonPolicy";

  constructor() {
    super();

    // 存储图像信息
    this.figures = new ArrayList();

    // 存储点信息
    this.points = new ArrayList();

    // 最近一个点和鼠标位置的点的连接线
    this.activeLine = null;

    // 起始点吸附区域半径
    this.adsorbAreaRadius = 5;

    // 开始绘制
    this.startDraw = false;

    // 是否闭合
    this.isClosed = false;

    this.x = 0;
    this.y = 0;
  }

  onKeyUp(canvas, keyCode) {
    // ESC
    keyCode === 27 && this.cancelDraw();
  }

  // 鼠标点下 起 - 始  多边形绘制完成
  onMouseDown(canvas, x, y) {
    this.x = x;
    this.y = y;

    this.startDraw = true;

    this.points.push({
      x: this.x,
      y: this.y
    });

    if (this.isClosed) {
      this.finishCurrentDraw();
      return;
    }
    this.createRectPoint();
    this.createActiveLine(this.x, this.y);
    this.createLineByPoints();
  }

  onMouseMove(canvas, x, y) {
    if (!this.startDraw || !this.figures.getSize()) {
      return;
    }
    this.createActiveLine(x, y);

    this.closeArea(x, y);
  }

  // 创建矩形点
  createRectPoint() {
    let point = new namespace.shape.Rectangle({
      width: RECT_POINT_WIDTH,
      height: RECT_POINT_HEIGHT,
      bgColor: RECT_POINT_BG_COLOR,
      strokeWidth: 0.5
    });

    point.setCanvas(this.canvas);

    point.setPosition(
      this.x - RECT_POINT_WIDTH / 2,
      this.y - RECT_POINT_HEIGHT / 2
    );

    this.figures.add(point);
  }

  // 创建活动的线
  createActiveLine(dx, dy) {
    if (!this.activeLine) {
      this.activeLine = new namespace.shape.Line(this.x, this.y, dx, dy);
      this.activeLine.setCanvas(this.canvas);
      this.activeLine.hide = () => this.activeLine.setCanvas(null);
    }
    this.activeLine.setStartPoint(this.x, this.y);
    this.activeLine.setEndPoint(dx, dy);
  }

  // 创建直线
  createLineByPoints() {
    let size = this.points.getSize();

    if (size < 2) {
      return;
    }

    let end = this.points.pop();
    let start = this.points.pop();

    let line = new namespace.shape.Line(
      start.x,
      start.y,
      end.x,
      end.y
    ).setCanvas(this.canvas);

    this.points.push(start);
    this.points.push(end);

    this.figures.push(line);
  }

  closeArea(dx, dy) {
    // 是否可以吸附
    if (!this.isAdsorb(dx, dy)) {
      this.figures.getSize() > 1 &&
        this.figures.first().setBgColor(RECT_POINT_BG_COLOR);
      this.isClosed = false;
      return;
    }

    let startPoint = this.points.first();
    this.activeLine.setEndPoint(startPoint.x, startPoint.y);
    this.figures.getSize() > 1 &&
      this.figures.first().setBgColor(RECT_POINT_HIGHLIGHT_BG_COLOR);

    this.isClosed = true;
  }

  // 是否吸附到起点
  isAdsorb(dx, dy) {
    if (this.points.isEmpty()) {
      return false;
    }
    let startPoint = this.points.first();
    let distance = Math.sqrt(
      Math.pow(startPoint.x - dx, 2) + Math.pow(startPoint.y - dy, 2)
    );
    return distance <= this.adsorbAreaRadius;
  }

  // 结束当前绘图,初始化下次绘图
  finishCurrentDraw() {
    // 移除最后一个点. path 自己闭合
    this.points.pop();
    let polygon = new namespace.shape.Polygon({ vertices: this.points });
    this.canvas.addFigure(polygon);
    this.clearHistoryData();
  }

  clearHistoryData() {
    if (!this.startDraw && !this.isClosed) {
      return;
    }

    this.clearFigures();
    this.points = new ArrayList();
    this.activeLine = null;
    this.startDraw = false;
    this.isClosed = false;
    this.x = 0;
    this.y = 0;
  }

  clearFigures() {
    let figures = this.figures.asArray();
    this.activeLine && this.activeLine.hide();

    for (let key in figures) {
      let figure = figures[key];
      figure.setCanvas(null);
    }

    this.figures = new ArrayList();
  }

  cancelDraw() {
    this.clearHistoryData();
  }
}

namespace.policy.canvas.PolygonPolicy = PolygonPolicy;
